package com.tech.cloudapp.util;

import org.hibernate.validator.HibernateValidator;
import org.springframework.util.ClassUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.DataBinder;
import org.springframework.validation.SmartValidator;
import org.springframework.validation.beanvalidation.SpringValidatorAdapter;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validation;
import javax.validation.Validator;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

public class ValidatorUtils {
	private static Validator validator;
	private static Validator fastValidator;
	private static SmartValidator validatorAdapter;

	static {
		// 详细返回模式
		validator = Validation.byProvider(HibernateValidator.class)
			.configure()
			.failFast(false)
			.buildValidatorFactory()
			.getValidator();
        // 快速返回模式
		fastValidator =  Validation.byProvider(HibernateValidator.class)
			.configure()
			.failFast(false)
			.buildValidatorFactory()
			.getValidator();
	}

	public static Validator getValidator() {
		return validator;
	}

	private static SmartValidator getValidatorAdapter(Validator validator) {
		if (validatorAdapter == null) {
			validatorAdapter = new SpringValidatorAdapter(validator);
		}
		return validatorAdapter;
	}

	/**
	 * 校验参数，用于普通参数校验 [未测试！]
	 *
	 * @param
	 */
	public static void validateParams(Object... params) {
		Set<ConstraintViolation<Object>> constraintViolationSet = validator.validate(params);

		if (!constraintViolationSet.isEmpty()) {
			throw new ConstraintViolationException(constraintViolationSet);
		}
	}

	/**
	 * 校验对象
	 *
	 * @param object
	 * @param groups
	 * @param <T>
	 */
	public static <T> void validate(T object, Class<?>... groups) {
		Set<ConstraintViolation<T>> constraintViolationSet = fastValidator.validate(object, groups);

		if (!constraintViolationSet.isEmpty()) {
			throw new ConstraintViolationException(constraintViolationSet);
		}
	}

	/**
	 * 校验对象
	 *
	 * @param object
	 * @param <T>
	 */
	public static <T> void validate(T object) {
		Set<ConstraintViolation<T>> constraintViolationSet = validator.validate(object);

		if (!constraintViolationSet.isEmpty()) {
			throw new ConstraintViolationException(constraintViolationSet);
		}
	}

	/**
	 * 校验对象
	 * 使用与 Spring 集成的校验方式。
	 *
	 * @param object 待校验对象
	 * @param groups 待校验的组
	 * @throws BindException
	 */
	public static <T> void validateBySpring(T object, Class<?>... groups)
		throws BindException {
		DataBinder dataBinder = getBinder(object);
		dataBinder.validate((Object[]) groups);

		if (dataBinder.getBindingResult().hasErrors()) {
			throw new BindException(dataBinder.getBindingResult());
		}
	}

	private static <T> DataBinder getBinder(T object) {
		DataBinder dataBinder = new DataBinder(object, ClassUtils.getShortName(object.getClass()));
		dataBinder.setValidator(getValidatorAdapter(validator));
		return dataBinder;
	}

	/**
	 * 判断是否为整数
	 * @param str 传入的字符串
	 * @return 是整数返回true, 否则返回false
	 * @param str
	 * @return
	 */
	public static boolean isInteger(String str) {
		Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");
		return pattern.matcher(str).matches();
	}

	public static Map<String, String> validateResult(Object bean)
	{
		Map<String, String> validateMap = new HashMap<>();
		Set<ConstraintViolation<Object>> constraintViolationSet = validator.validate(bean);
		for(ConstraintViolation<Object> c : constraintViolationSet)
		{
			validateMap.put(c.getPropertyPath().toString(),c.getMessage());
		}
		return validateMap;
	}


	public static Map<String, String> fastValidateResult(Object bean)
	{
		Map<String, String> validateMap = new HashMap<>();
		Set<ConstraintViolation<Object>> constraintViolationSet = fastValidator.validate(bean);
		for(ConstraintViolation<Object> c : constraintViolationSet)
		{
			validateMap.put(c.getPropertyPath().toString(),c.getMessage());
		}
		return validateMap;
	}

}
